package com.gxar.uaa.server.db.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gxar.common.entity.PageResult;
import com.gxar.common.entity.Result;
import com.gxar.common.entity.login.LoginUserThread;
import com.gxar.common.entity.login.UserProfile;
import com.gxar.common.exception.APIRuntimeException;
import com.gxar.common.utils.PageUtils;
import com.gxar.uaa.api.dto.role.SysRole;
import com.gxar.uaa.api.enums.DataScope;
import com.gxar.uaa.server.base.common.constant.CommonConstant;
import com.gxar.uaa.server.base.model.ResultCodeEnum;
import com.gxar.uaa.server.base.model.role.mapper.RoleMapStruct;
import com.gxar.uaa.server.base.model.role.vo.BaseRoleVO;
import com.gxar.uaa.server.base.model.role.vo.request.RoleCreateRequest;
import com.gxar.uaa.server.base.model.role.vo.request.RoleUpdateRequest;
import com.gxar.uaa.server.base.model.role.vo.response.RoleCreateResponse;
import com.gxar.uaa.server.base.model.role.vo.response.RoleInfoResponse;
import com.gxar.uaa.server.base.model.role.vo.response.RoleUpdateResponse;
import com.gxar.uaa.server.base.model.role.vo.response.RoleUserResponse;
import com.gxar.uaa.server.base.reference.UserReference;
import com.gxar.uaa.server.db.mapper.SysRoleMapper;
import com.gxar.uaa.server.db.mapper.SysUserRoleMapper;
import com.gxar.uaa.server.db.model.SysRoleEntity;
import com.gxar.uaa.server.db.model.SysRoleUserEntity;
import com.gxar.uaa.server.db.repository.SysRoleRepository;
import com.gxar.uaa.server.db.repository.SysRoleUserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author linsy
 * @version 1.0
 * @created 2024/1/24 14:34
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleService {

    private final SysUserRoleMapper userRoleMapper;
    private final SysRoleMapper roleMapper;
    private final SysRoleRepository roleRepository;
    private final SysRoleUserRepository sysRoleUserRepository;
    private final UserReference userReference;

    /**
     * 根据用户id查询角色
     *
     * @param app    app
     * @param userId 用户id
     * @return 角色信息
     */
    public List<SysRole> findRolesByUserId(String app, Long userId) {
        return userRoleMapper.findRolesByUserId(app, userId);
    }

    /**
     * 分页查询
     *
     * @param pageNum  当前页
     * @param pageSize 页大小
     * @return 角色信息
     */
    public Result<PageResult<RoleInfoResponse>> pageList(int pageNum, int pageSize) {
        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<SysRoleEntity> roleEntityList = roleMapper.findByApp(LoginUserThread.get().getApp());
        if (CollectionUtils.isEmpty(roleEntityList)) {
            return Result.success(new PageResult<>());
        }
        List<RoleInfoResponse> roleInfoResponses = RoleMapStruct.INSTANCE.entitiesToInfoList(roleEntityList);
        PageInfo<RoleInfoResponse> roleInfoResponsePageInfo = new PageInfo<>(roleInfoResponses);
        roleInfoResponsePageInfo.setTotal(page.getTotal());
        return PageUtils.getPageResult(roleInfoResponsePageInfo, roleInfoResponses);
    }

    /**
     * 查询所有角色
     *
     * @return 所有角色
     */
    public List<RoleInfoResponse> findAll() {
        List<SysRoleEntity> roleEntityList = roleMapper.findByApp(LoginUserThread.get().getApp());
        if (CollectionUtils.isEmpty(roleEntityList)) {
            return Collections.emptyList();
        }
        return RoleMapStruct.INSTANCE.entitiesToInfoList(roleEntityList);
    }

    /**
     * 创建角色
     *
     * @param request 请求
     * @return 响应
     */
    @Transactional(rollbackFor = Throwable.class)
    public RoleCreateResponse create(RoleCreateRequest request) {
        if (!request.getApp().equals(CommonConstant.ADMIN_ROLE_NAME)
                && request.getDataScope().equals(DataScope.ALL.name())) {
            throw new APIRuntimeException(ResultCodeEnum.ONLY_ADMIN_DATA_SCOPE_ALL);
        }
        this.checkExist(request);
        SysRoleEntity sysRoleEntity = RoleMapStruct.INSTANCE.createToEntity(request);
        sysRoleEntity.setCreatedAt(new Date());
        sysRoleEntity.setCreator(LoginUserThread.get().getMobile());
        sysRoleEntity.setUpdatedAt(new Date());
        SysRoleEntity save = roleRepository.save(sysRoleEntity);
        return RoleMapStruct.INSTANCE.entityToCreate(save);
    }

    /**
     * 更新角色
     *
     * @param id      角色id
     * @param request 请求
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    public RoleUpdateResponse update(Long id, RoleUpdateRequest request) {
        if (!request.getApp().equals(CommonConstant.ADMIN_ROLE_NAME)
                && request.getDataScope().equals(DataScope.ALL.name())) {
            throw new APIRuntimeException(ResultCodeEnum.ONLY_ADMIN_DATA_SCOPE_ALL);
        }
        Optional<SysRoleEntity> roleEntityOptional = roleRepository.findById(id);
        if (!roleEntityOptional.isPresent()) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_EXISTS);
        }
        SysRoleEntity sysRoleEntity = roleEntityOptional.get();
        if (!sysRoleEntity.getCode().equals(request.getCode())) {
            this.checkExist(request);
        }
        SysRoleEntity roleEntity = RoleMapStruct.INSTANCE.updateToEntity(request);
        roleEntity.setId(id);
        roleEntity.setCreatedAt(sysRoleEntity.getCreatedAt());
        roleEntity.setCreator(sysRoleEntity.getCreator());
        roleEntity.setUpdatedAt(new Date());
        roleEntity.setOperator(LoginUserThread.get().getMobile());
        SysRoleEntity saved = roleRepository.save(roleEntity);
        return RoleMapStruct.INSTANCE.entityToUpdate(saved);
    }

    /**
     * 角色删除
     *
     * @param id id
     */
    @Transactional(rollbackFor = Throwable.class)
    public void delete(Long id) {
        Optional<SysRoleEntity> roleEntityOptional = roleRepository.findById(id);
        if (!roleEntityOptional.isPresent()) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        SysRoleEntity sysRoleEntity = roleEntityOptional.get();
        if (!sysRoleEntity.getApp().equals(LoginUserThread.get().getApp())) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        if (CommonConstant.ADMIN_ROLE_NAME.equals(sysRoleEntity.getCode())) {
            throw new APIRuntimeException(ResultCodeEnum.ADMIN_ROLE_NOT_DELETE);
        }
        roleRepository.delete(sysRoleEntity);
    }

    /**
     * 用户分配角色
     *
     * @param userProfile
     * @param userId      用户ID
     * @param roleIds     角色ID集合
     */
    @Transactional(rollbackFor = Throwable.class)
    public void setRoleToUser(UserProfile userProfile, Long userId, Set<Long> roleIds) {
        List<SysRoleEntity> roleEntities = roleRepository.findAllById(roleIds);
        if (CollectionUtils.isEmpty(roleEntities)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        this.checkAdmin(userProfile, roleEntities);
        userRoleMapper.deleteInUser(Collections.singletonList(userId));
        List<SysRoleUserEntity> roleMenu = new ArrayList<>(roleIds.size());
        roleIds.forEach(e -> {
            SysRoleUserEntity entity = new SysRoleUserEntity();
            entity.setRoleId(e);
            entity.setUserId(userId);
            entity.setCreator(userProfile.getMobile());
            entity.setCreatedAt(new Date());
            roleMenu.add(entity);
        });
        sysRoleUserRepository.saveAll(roleMenu);
    }

    /**
     * 校验用户是否具备操作管理员角色
     *
     * @param userProfile  用户
     * @param roleEntities 角色列表
     */
    private void checkAdmin(UserProfile userProfile, List<SysRoleEntity> roleEntities) {
        SysRoleEntity adminRole = roleEntities.stream().filter(e -> CommonConstant.ADMIN_ROLE_NAME.equals(e.getCode())).findFirst().orElse(null);
        Long id = userProfile.getId();
        // 操作管理员的用户
        if (Objects.nonNull(adminRole)) {
            // 校验用户是否有管理员权限
            List<SysRole> roleList = userRoleMapper.findRolesByUserId(userProfile.getApp(), id);
            boolean admin = roleList.stream().anyMatch(e -> e.getId().equals(adminRole.getId()));
            if (!admin) {
                throw new APIRuntimeException(ResultCodeEnum.ROLE_ADD_USER_NO_PERMISSION);
            }
        }
    }

    public <T extends BaseRoleVO> void checkExist(T request) {
        String code = request.getCode();
        SysRoleEntity roleEntity = roleMapper.findByCode(request.getApp(), code);
        if (Objects.nonNull(roleEntity)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_CODE_EXIST);
        }
    }

    /**
     * 批量删除用户角色关系
     *
     * @param userId 用户ID
     */
    @Transactional(rollbackFor = Throwable.class)
    public void batchDelete(List<Long> userId) {
        if (CollectionUtils.isEmpty(userId)) {
            return;
        }
        userRoleMapper.deleteInUser(userId);
    }

    /**
     * 删除角色用户
     *
     * @param userProfile 用户配置
     * @param userId      用户ID
     * @param roleIds     角色ID
     */
    @Transactional(rollbackFor = Throwable.class)
    public void deleteRoleUser(UserProfile userProfile, Long userId, Set<Long> roleIds) {
        List<SysRoleEntity> roleEntities = roleRepository.findAllById(roleIds);
        if (CollectionUtils.isEmpty(roleEntities)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        this.checkAdmin(userProfile, roleEntities);
        userRoleMapper.deleteInRoleId(userId, roleIds);
    }

    /**
     * 分页查询角色的用户列表
     *
     * @param userProfile
     * @param id          角色id
     * @param pageNum     当前页
     * @param pageSize    页记录数
     * @return 用户信息
     */
    public Result<PageResult<RoleUserResponse>> roleUsers(UserProfile userProfile, Long id, int pageNum, int pageSize) {
        SysRoleEntity roleEntity = roleMapper.findById(userProfile.getApp(), id);
        if (Objects.isNull(roleEntity)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<SysRoleUserEntity> roleUserEntityList = userRoleMapper.queryPage(id);
        if (CollectionUtils.isEmpty(roleUserEntityList)) {
            return Result.success(new PageResult<>());
        }
        List<Long> userIdList = roleUserEntityList.stream().map(SysRoleUserEntity::getUserId).collect(Collectors.toList());
        List<UserProfile> userProfiles = userReference.batchProfileByAuthorize(userIdList, userProfile.getApp(), userProfile.getPlatform());
        Map<Long, UserProfile> userProfileMap = Optional.ofNullable(userProfiles).orElse(Collections.emptyList()).stream().collect(Collectors.toMap(UserProfile::getId, t -> t, (t1, t2) -> t1));
        List<RoleUserResponse> responses = RoleMapStruct.INSTANCE.roleUsersToResponses(roleUserEntityList);
        for (RoleUserResponse response : responses) {
            UserProfile profile = userProfileMap.get(response.getUserId());
            if (Objects.nonNull(profile)) {
                response.setPhone(profile.getMobile());
                response.setUsername(profile.getUsername());
            }
        }
        PageInfo<RoleUserResponse> responsePageInfo = new PageInfo<>(responses);
        responsePageInfo.setPageNum(pageNum);
        responsePageInfo.setTotal(page.getTotal());
        return PageUtils.getPageResult(responsePageInfo, responses);
    }

    /**
     * 查询用户角色列表
     *
     * @param app    app
     * @param userId 用户ID
     * @return 响应
     */
    public List<RoleInfoResponse> userRoles(String app, Long userId) {
        List<SysRole> roleList = userRoleMapper.findRolesByUserId(app, userId);
        return RoleMapStruct.INSTANCE.sysRolesToRoleInfos(roleList);
    }

}
